#pragma once
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iostream>
#include <vector>


#pragma comment(lib, "Ws2_32.lib")

/**
 *                                  *******************
 *                                  * IO多路复用服务器类 *
 *                                  *******************
 *
 *使用示例：
 *
 * WSAPollServer server;
 * WSAPollClient client;
 *
 * 先启动服务器
 * std::thread serverThread([&server]() {
 *     server.start();
 * });
 *
 * 等待服务器启动
 * std::this_thread::sleep_for(std::chrono::seconds(2));
 * std::cout << "Server started!" << std::endl;
 *
 * 然后启动客户端
 * std::thread clientThread([&client]() {
 *     client.start();
 * });
 *
 * 等待客户端器启动
 * std::this_thread::sleep_for(std::chrono::seconds(2));
 *
 * 客户端发送消息给服务器
 * std::thread clientSendThread([&client]() {
 *      client.sendMessage("Hello from client");
 * );
 *
 * 等待线程结束
 * serverThread.join();
 * clientThread.join();
 * clientSendThread.join();
 *
 */
class WSAPollServer {

private:
    SOCKET m_serverSocket = INVALID_SOCKET;
    std::vector<pollfd> m_pollfds;
    bool m_running = false;

private:

    /**
     *初始化WinSock
     * @return true 初始化成功 false 初始化失败
     */
    bool initializeWinSock() {
        WSAData data;
        if (WSAStartup(MAKEWORD(2,2), &data) == 0) return true;
        std::cout << " Server:WSAStartup failed: " << WSAGetLastError() << std::endl;
        return false;
    }

    /**
     * 创建服务器套接字
     * @return true 创建成功 false 创建失败
     */
    bool createServerSocket() {
        this->m_serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

        if (m_serverSocket == INVALID_SOCKET) {
            std::cout  << "Socket creation failed: " << WSAGetLastError() << std::endl;
            return false;
        }

        int opt = 1;
        if (setsockopt(m_serverSocket, SOL_SOCKET, SO_REUSEADDR,(char*)&opt, sizeof(opt)) == SOCKET_ERROR) {
            std::cout << "Set socket option failed: " << WSAGetLastError() << std::endl;
            return false;
        }

        return true;
    }

    /**
     * 绑定和监听地址
     * @return  true 成功 false 失败
     */
    bool bindAndListen() {

        sockaddr_in serverAddr{};
        serverAddr.sin_family = AF_INET;
        serverAddr.sin_addr.s_addr = INADDR_ANY;
        serverAddr.sin_port = htons(8081);

        if (bind(m_serverSocket, (sockaddr*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR) {
            std::cout  << "Bind failed: " << WSAGetLastError() << "\n";
            return false;
        }

        if (listen(m_serverSocket, SOMAXCONN) == SOCKET_ERROR) {
            std::cout << "Listen failed: " << WSAGetLastError() << "\n";
            return false;
        }

        this->m_pollfds.push_back({this->m_serverSocket,POLLIN,0});
        return true;
    }

    /**
     * 处理事件
     */
    void processEvents() {

        size_t i = 0;



        while (i < this->m_pollfds.size()) {


            //无新事件不处理
            if (this->m_pollfds[i].revents == 0 ) {
                std::cout << "Poll aborted\n";
            }


            //有新链接，则处理
            else if (this->m_pollfds[i].fd == this->m_serverSocket)this->handleNewConnection();

            //处理服务器数据
            else if (!this->handleClientData(i)) continue; //处理数据失败，会删除m_pollfds数组的参数，不用i++


            i++;
        }

    }

    /**
     * 处理新链接
     */
    void handleNewConnection() {

        sockaddr_in clientAddr{};
        int addrLength = sizeof(clientAddr);
        SOCKET clientSocket  = accept(this->m_serverSocket, (sockaddr*)&clientAddr, &addrLength);

        if (clientSocket == INVALID_SOCKET) {
            std::cout << "Accept failed: " << WSAGetLastError() << std::endl;
            return;
        }

        if (this->m_pollfds.size() >= 64 + 1) {
            std::cout << "Max clients reached. Connection closed." << std::endl;
            closesocket(clientSocket);
            return;
        }

        this->m_pollfds.push_back({clientSocket, POLLIN, 0});

        char ipStr[INET_ADDRSTRLEN];
        inet_ntop(AF_INET, &(clientAddr.sin_addr), ipStr, INET_ADDRSTRLEN);
        std::cout << "server:New client connected: " << ipStr << ":" << ntohs(clientAddr.sin_port) << std::endl;



    }

    /**
     * 处理服务器数据
     * @param index
     * @return ture 成功 false 失败
     */
    bool handleClientData(size_t index) {

        std::cout << "server::handleClientData" << std::endl;
        char buffer[1024];
        int bytesReceived = recv(this->m_pollfds[index].fd, buffer, 1024, 0);

        //客户端关闭或者接受异常
        if (bytesReceived <= 0) {
            closesocket(this->m_pollfds[index].fd);
            this->m_pollfds.erase(m_pollfds.begin() + index);
            std::cout << "Client disconnected"<< std::endl;
            return false;
        }

        buffer[bytesReceived] = '\0';
        std::cout << "Server_Received: " << buffer << std::endl;

        //回应服务器
        send(m_pollfds[index].fd, buffer, bytesReceived, 0);
        return true;
    }

    /**
     * 运行循环事件
     */
    void runEventLoop() {


        while (this->m_running) {
            int ret = WSAPoll(this->m_pollfds.data(), (ULONG)this->m_pollfds.size(), 1000);
            if (ret == SOCKET_ERROR) {
                std::cout << "Poll error: " << WSAGetLastError() << std::endl;
                break;
            }

            if (ret == 0) continue;//超时

            this->processEvents();
        }
    }

public:
    WSAPollServer() = default;
    ~WSAPollServer() {
        this->close();
    }

    /**
     * 启动服务器
     */
    void start() {
        if (!this->initializeWinSock()
            || !this->createServerSocket()
            || !this->bindAndListen()) return;

        this->m_running = true;

        //处理事件
        runEventLoop();
    }

    /**
     *关闭服务器
     */
    void close() {
        //清除m_pollfds的数据
        std::vector<pollfd>::iterator it = this->m_pollfds.begin();
        while (it != this->m_pollfds.end()) {
            if (it->fd != INVALID_SOCKET) closesocket(it->fd);
            it++;
        }

        this->m_pollfds.clear();

        if (this->m_serverSocket != INVALID_SOCKET) {
            closesocket(this->m_serverSocket);
            this->m_serverSocket = INVALID_SOCKET;
        }

        WSACleanup();

        this->m_running  = false;
    }

};